home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
asynch.pqs
/
asynch.pas
Wrap
Pascal/Delphi Source File
|
1984-12-20
|
12KB
|
254 lines
Type tComPort = (Com1, Com2);
tBaud = (b110, b150, b300, b600, b1200, b2400, b4800, b9600);
tParity = (pSpace, pOdd, pMark, pEven, pNone);
tDatabits = (d5, d6, d7, d8);
tStopbits = (s1, s2);
Type tSaveVector = record { Saved Com interrupt vector }
IP: integer;
CS: integer;
end;
Type regpak =
record AX, BX, CX, DX, BP, SI, DI, DS, ES, FLAGS:integer end;
Const ourDS: integer = -1; { Will be init to contents of our DS
for later use in Interrupt routine }
{ Define address adders for the various
Async card registers. }
Const RBR = $00; { xF8 Receive Buffer Register }
THR = $00; { xF8 Transmitter Holding Register }
IER = $01; { xF9 Interrupt Enable Register }
IIR = $02; { xFA Interrupt Identification Register }
LCR = $03; { xFB Line Control Register }
MCR = $04; { xFC Modem Control Register }
LSR = $05; { xFD Line Status Register }
MSR = $06; { xFE Modem Status Register }
DLL = $00; { xF8 Divisor Latch Least Significant }
DLM = $01; { xF9 Divisor Latch Most Significant }
{ ASynch Interrupt Masks }
imlist: array[Com1..Com2] of integer = ($EF, $F7);
{ ASynch hardware interrupt addresses }
ivlist: array[Com1..Com2] of integer = ($000C, $000B);
PICCMD = $20; { 8259 Priority Interrupt Controller }
PICMSK = $21; { 8259 Priority Interrupt Controller }
{ Asynch base port addresses are
in the ROM BIOS data area }
Var ComBaseAddr: array[Com1..Com2] of integer Absolute $0040:$0000;
{
Define a ring buffer for Asynch_Interrupt to write into
and ReadCom to read from.
}
Var ringbuf: array[0..8000] of char;
readptr, writptr: 0..80000; { Index which ReadCom will next read from
Index which Asunch_Interrupt will next
write into. If readptr=writptr then
the buffer is empty. }
Var LSRstat: byte; { Line Status Reg at interrupt }
ComSaveVec: tSaveVector; { saved Async Interrupt vector }
ComBase :integer; { Opened Com port base address }
ActiveComPort: tComPort; { Opened Com }
imvalue: integer; { Interrupt Mask value in use }
type lstring = string[255];
Procedure SwapIntVector(IntVect: integer;
Var SaveVector: tSaveVector);
Var dosregs: regpak;
Begin
inline($FA); { cli disable interrupts }
With dosregs Do Begin
ax := ($35 * 256) + IntVect;
MsDos(dosregs); { DOS function 35 - get vector }
ds := SaveVector.CS;
dx := SaveVector.IP;
SaveVector.CS := es;
SaveVector.IP := bx;
ax := ($25 * 256) + IntVect;
MsDos(dosregs); { DOS function 25 - set vector }
End;
inline($FB); { sti re-enable ints }
End;
{ This routine gets control upon an Asynch Interrupt }
Procedure Asynch_Interrupt;
Var dummy: array[1..8] of integer; { Leave room for our push's }
MSRstat, IIRreg: byte;
Begin
{
BP-4 Return IP
BP-2 Return CS
BP---> Caller's BP
}
{ Push regs but DON'T enable - we can't
handle another interrupt now }
inline($50/$53/$51/$52/$57/$56/$06);
inline($1E); { push ds save ds, also }
inline($2E/$8E/$1E/ourDS); { mov DS,CS:ourDS ;Setup our DS }
IIRreg := PORT[ComBase + IIR]; { Get Interrupt Identification }
If (IIRreg and $01) = 0 then Begin { If interrupt pending }
IIRreg := IIRreg and $06; { Leave bits 2 and 1 on }
Case IIRreg of { Determine cause of interrupt (we
actually only expect (and handle)
the Data Available interrupt }
$04: Begin { Received Data Available Interrupt }
If LSRstat = 0 then Begin { If Line Status is OK }
{ If there is Room in Buffer }
If (SUCC(writptr) <> readptr then Begin
{ Receive byte into our buffer }
ringbuf[writptr] := CHR(PORT[ComBase + RBR]);
{ Increment writptr }
writptr := SUCC(writptr) mod 256;
End
{ If buffer full, pretend overrun }
Else LSRstat := (LSRstat or $02);
End;
End;
$06: LSRstat := PORT[ComBase + LSR] and $1E;
$02: Begin End;
$00: MSRstat := PORT[ComBase + MSR];
Else Begin End;
End; { Case }
End;
PORT[PICCMD] := $20; { Send End Of Interrupt to 8259 }
inline($1F); { pop ds }
inline($07/$5E/$5F/$5A/$59/$5B/$58); { pop rest of regs }
inline($89/$EC); { mov sp,bp }
inline($5D); { pop bp }
inline($CF); { iret ;Return from interrupt }
End;
{ Open COM1 or COM2, a la Basic }
Procedure OpenCom(ComPort: tComPort;
Baud: tBaud;
Parity: tParity;
Databits: tDatabits;
Stopbits: tStopbits);
Const baudcode: array[b110..b9600] of integer =
($417, $300, $180, $C0, $60, $30, $18, $0C);
paritycode: array[pSpace..pNone] of byte =
($38, $08, $28, $18, $00);
databitscode: array[d5..d8] of byte = ($00, $01, $02, $03);
stopbitscode: array[s1..s2] of byte = ($00, $04);
Var LCRreg: byte;
Begin
{ Init the Const "ourDS" for use by
the Async_Interrupt routine }
inline($1E); { push ds }
inline($2E/$8F/$06/ourDS); { cs:pop ourDS }
{ Swap Com interrupt vector }
With ComSaveVec Do Begin
CS := CSEG;
IP := OFS(Asynch_Interrupt);
End;
SwapIntVector(ivlist[ComPort], ComSaveVec);
ActiveComPort := ComPort;
inline($CD/$01);
ComBase := ComBaseAddr[ComPort];
LSRstat := 0; { Reset LSR status }
imvalue := imlist[ComPort]; { Select Interrupt Mask val }
ComBase := ComBaseAddr[ComPort]; { Select Input Port }
readptr := 0; { Init buffer pointers }
writptr := 0; { Init buffer pointers }
PORT[PICMSK] := PORT[PICMSK] and imvalue; { Enable ASynch Int }
PORT[IER+ComBase] := $01; { Enable some interrupts }
{ Note: OUT2, despite documentation,
MUST be ON, to enable interrupts }
PORT[MCR+ComBase] := $0B; { Set RTS, DTR, OUT2 }
LCRreg := $80; { Set Divisor Latch Access Bit in LCR }
LCRreg := LCRreg or paritycode[Parity]; { Setup Parity }
LCRreg := LCRreg or databitscode[Databits];{ Setup # data bits }
LCRreg := LCRreg or stopbitscode[Stopbits];{ Setup # stop bits }
PORT[LCR+ComBase] := LCRreg; { Set Parity, Data and Stop Bits
and set DLAB }
PORT[DLM+ComBase] := Hi(baudcode[Baud]); { Set Baud rate }
PORT[DLL+ComBase] := Lo(baudcode[Baud]); { Set Baud rate }
PORT[LCR+ComBase] := LCRreg and $7F; { Reset DLAB }
inline($CD/$01);
End;
{ Close any initialized COM }
Procedure CloseCom;
Begin
{ Disable Async interrupt }
PORT[PICMSK] := PORT[PICMSK] or ($FF - imvalue);
PORT[IER+ComBase] := $00; { Disable Data Avail interrupt }
{ Restore Com interrupt vector }
SwapIntVector(ivlist[ActiveComPort], ComSaveVec);
End;
{
Read a stream of data from the initialized COM port. If Line
Status is not currently zero, then return immediately with
the Line Status byte. If there is no data currently in the
buffer then return stream:=null with function:=0. If there
is data in the buffer, then return all the data up to, but
not including, a CR($0D). If a CR is not found in the buffer
then loop here until one arrives.
}
Function ReadCom(var stream: lstring): byte;{ Returned LSR, or zero}
Function ReadChar: char; { Return char, or SPIN !!!! }
Begin
If readptr = writptr then
Repeat Begin End Until (readptr <> writptr);
ReadChar := ringbuf[readptr];
readptr := SUCC(readptr) mod 256;
End;
Begin
stream[0] := CHAR($00); { Init returned string to null }
ReadCom := LSRstat; { Return LSR, or zero }
If LSRstat = 0 then Begin
If readptr <> writptr then Begin { If buffer not empty }
Repeat Begin { Get chars from ring buffer}
{ Increment returned string len }
stream[0] := CHAR(ORD(SUCC(stream[0])));
{ Get a char from buffer, or SPIN}
stream[ORD(stream[0])] := ReadChar;
End
Until (stream[ORD(stream[0])] = CHR($0D)); { Until see a CR }
stream[0] := CHR(ORD(stream[0]) - 1); { strip the CR }
End;
End;
End;
{
Write a stream of data to the initialized COM port, then
append a CR and LF.
}
Procedure WriteCom(stream: lstring);
Var LSRreg: byte;
i: integer;
Begin
inline($FA); { disable interrupts until we get all
the data sent. }
For i := 1 to LENGTH(stream) Do Begin
{ Spin until Transmitter Holding
Register (THRE) is empty }
Repeat LSRreg := (PORT[LSR+ComBase] and $20) Until LSRreg <> 0;
PORT[THR+ComBase] := ORD(stream[i]); { Output the caharacter}
End;
Repeat LSRreg := (PORT[LSR+ComBase] and $20) Until LSRreg <> 0;
PORT[THR+ComBase] := $0D; { Output a CR }
Repeat LSRreg := (PORT[LSR+ComBase] and $20) Until LSRreg <> 0;
PORT[THR+ComBase] := $0A; { Output a LF }
inline($FB); { Reenable interrupts }
End;
begin end.